package com.saturday.web.advice;

import cn.hutool.core.codec.Base64;
import com.saturday.common.constants.CommonConsts;
import com.saturday.common.model.vo.ResponseVO;
import com.saturday.web.translates.annotaion.JsonTranslater;
import com.saturday.web.translates.annotaion.JsonTranslaters;
import com.saturday.web.translates.processor.DictProcessor;
import com.saturday.web.translates.processor.TranslateProcessor;
import com.saturday.web.translates.service.TranslateService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@RestControllerAdvice
@Component
public class WebResponseBodyAdvice implements ResponseBodyAdvice {
    @Autowired(required = false)
    Map<String, TranslateService> translateServiceMap;

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (o instanceof ResponseVO) {
            /**
             * 此处认为内部服务不会返回ResponseVO，而是具体的业务对象，所以如果走到下面的逻辑说明发生了feign调用但是并不是feign层抛出的BusinessException而发生的异常
             * 例如：前后端加解密造成的body miss或者MVC对于http method不支持等错误
             */
            ResponseVO responseVO = (ResponseVO) o;
            if (null != RequestContextHolder.getRequestAttributes() && null != ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse()) {
                HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
                // 如果不存在需要截取后三位传入服务调用者，由服务调用者重组满足前端规范的错误码
                if (StringUtils.isEmpty(response.getHeader(CommonConsts.FEIGN_RESPONSE_HEADER_ERROR_CODE_KEY))) {
                    response.setHeader(CommonConsts.FEIGN_RESPONSE_HEADER_ERROR_CODE_KEY, StringUtils.substring(responseVO.getCode().toString(), responseVO.getCode().toString().length() - 3, responseVO.getCode().toString().length()));
                }

                if (StringUtils.isEmpty(CommonConsts.FEIGN_RESPONSE_HEADER_ERROR_MESSAGE_KEY)) {
                    response.setHeader(CommonConsts.FEIGN_RESPONSE_HEADER_ERROR_MESSAGE_KEY, Base64.encode(responseVO.getMessage(), CommonConsts.UTF8));
                }
            }

            // 字典转化逻辑
            Object data = responseVO.getData();
            if (data != null) {
                //翻译器
                JsonTranslater jsonTranslater = methodParameter.getMethodAnnotation(JsonTranslater.class);
                JsonTranslaters jsonTranslaters = methodParameter.getMethodAnnotation(JsonTranslaters.class);
                List<JsonTranslater> translaterList = new ArrayList<>();
                if (jsonTranslater != null) {
                    translaterList.add(jsonTranslater);
                }
                if (jsonTranslaters != null && jsonTranslaters.value() != null) {
                    for (JsonTranslater translater : jsonTranslaters.value()) {
                        translaterList.add(translater);
                    }
                }
                if (CollectionUtils.isNotEmpty(translaterList)) {
                    TranslateProcessor.translate(translaterList, data, translateServiceMap);
                }

                //字典转换
                Object resultData = DictProcessor.jsonDict(data);
                responseVO.setData(resultData);
            }
            return responseVO;
        }
        return o;
    }

}
